package battleships;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.google.gson.Gson;

/**
 * Chat class.
 * Handles Social-related inputs, chatting, top lists and etc.
 */
@WebServlet("/Chat")
public class Chat extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final int serverId = BattleServlet.serverId;
	private static final ArrayList<String> history = new ArrayList<String>();
	// Chat, updates.
	public static final HashMap<Integer, BlockingQueue<String>> messages
					= new HashMap<Integer, BlockingQueue<String>>();
	// Updating userlist
	public static final HashMap<Integer, BlockingQueue<Boolean>> userlist
					= new HashMap<Integer, BlockingQueue<Boolean>>();
	
	Integer getUserId(HttpSession session) {
		synchronized(session) {
			Integer userId = (Integer)(session.getAttribute("userId"));
//			// If we redeploy, the following two lines will invalidate the old cookies
			Integer s_serverId = (Integer)(session.getAttribute("serverId"));
			if (userId == null || s_serverId == null || s_serverId != serverId) {
				userId = Handler.addUser();
				session.setAttribute("serverId", serverId);
				session.setAttribute("userId", userId);
			}
			return userId;
		}
	}
	
	public static void addMessageToAll(String msg) {
		try {
			for (Integer id : messages.keySet())
				messages.get(id).put(msg);
		} catch (InterruptedException e) { 
			throw new RuntimeException(e); 
		}
	}
	
	public static void addMessage(Integer userId, String msg) {
		try {
			messages.get(userId).put(msg);
		} catch (InterruptedException e) { 
			throw new RuntimeException(e); 
		}
	}
	
	public static void addListUpdateToAll() {
		try {
			for (Integer id : messages.keySet())
				userlist.get(id).put(new Boolean(true));
		} catch (InterruptedException e) { 
			throw new RuntimeException(e); 
		}
	}
	
	/* Returns a "update pack" users and games */
	public static String updatePack() {
		HashMap<String, String> result = new HashMap<String, String>();
		result.put("users", Handler.getWholeUserList(null));
		result.put("games", Handler.getWholeGameList());
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	private Boolean newUserList(Integer userId) {
		try {
			return userlist.get(userId).poll(20, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			throw new RuntimeException();
		}
	}
	
	// Get updates for chat
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		resp.setContentType("text/plain");
		PrintWriter out = resp.getWriter();
		Integer userId = getUserId(req.getSession());
		// Asking for the whole chat
		if (req.getParameter("all") != null) {
			for (String line : history)
				out.println(line);
			return;
		}
		// Asking for updates on user lists
		if (req.getParameter("updates") != null) {
			out.print(updatePack());
			return;
		}
		// Asking for userlist updates
		if (req.getParameter("userlistUpdates") != null) {
			// Want it now?
			if (req.getParameter("userlistUpdates").equals("now")) {
				out.print(Handler.getWholeUserList(userId));
				return;
			}
			// wait for a while
			Boolean result = this.newUserList(userId);
			if (result != null)
				out.print(Handler.getWholeUserList(userId));
			return;
		}
		// New messages from chat
		try {
			//System.err.println(userId + " waits.");
			String msg = messages.get(userId).poll(20, TimeUnit.SECONDS);
			if (msg != null)
				out.print(msg);
			System.err.println(userId + "(" + Handler.getUserName(userId) + ") chatwait got:"+msg);
		} catch (InterruptedException e) { 
			throw new RuntimeException(e); 
		}
		
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//synchronize session, make new user if needed
		Integer userId = getUserId(req.getSession());
		
		String msg = Handler.getUserName(userId) + ": " + req.getParameter("message");
		System.err.println("Chat: userId:"+userId+" posted: " + msg);
		// TODO: optimize history (remove old messages)
		history.add(msg);
		addMessageToAll(msg);
		resp.getWriter().print("success" + " " + msg);
	}

}
